/**
 * Copyright 2006 gworks.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 */
package org.javaongems.runtime.io;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;

import org.apache.commons.io.IOUtils;

/**
 * <p>Provides common io streaming behaviour
 * </p>
 * <p>Responsibilities:
 * <ul>
 * 	<li> load text content from a resource in the classpath
 * 	<li> provide a temporary stream that can be re-read repeatedly
 * </ul>
 * </p>
 * <p>Collaborators:
 * <ul>
 * 	<li> {@link ClassLoader}
 * 	<li> {@link Reader}, {@link Writer}
 * 	<li> {@link InputStream}, {@link OutputStream}
 * </ul>
 * </p>
 * @author Ashin Wimalajeewa (ash)
 *
 */
final public class TransferUtils {
	/**
	 * Command that loads text from resource accessible from the classpath
	 * @param clsThatCanResolveCpResource - a class whose class loader is able to resolve the specied resource
	 * @param cpResouce - a resource available from the classpath  
	 * @return a stringified version of the specified resource
	 * @throws IOException - if there are any problems when attempting to read the resource
	 */
	static public String transfer(Class clsThatCanResolveCpResource,
			String cpResouce) throws IOException {
		InputStream txtRes = clsThatCanResolveCpResource.getResourceAsStream(cpResouce);
		StringWriter sgw = new StringWriter();
		try {
			IOUtils.copy(txtRes, sgw);
		} finally {
			IOUtils.closeQuietly(txtRes);
		}
		return sgw.toString();
	}

	/**
	 * <p>Provides a temporary facility for writing for multiple subsequent reads.</p>
	 * <p>Responsibilities:
	 * <ul>
	 *  <li> Allocate a temporary file handle which can be later deleted
	 * 	<li> Stores a stream to disk for future repeatable reading
	 * </ul>
	 * </p>
	 * <p>Collaborators:
	 * <ul>
	 * 	<li> TemporaryBufferedInputStream - used for repeated reads
	 * </ul>
	 * </p>
	 */
	static public class TemporaryFileOuputStream extends OutputStream {
		File tempFile;
		private FileOutputStream fos;
		private boolean hasClosed;

		public TemporaryFileOuputStream() throws IOException {
			tempFile = File.createTempFile("tmp.fos", ".trans");
			fos = new FileOutputStream(tempFile);
		}

		public void close() throws IOException {
			fos.close();
			hasClosed = true;
		}

		public void flush() throws IOException {
			fos.flush();
		}

		public void write(byte b[], int off, int len) throws IOException {
			fos.write(b, off, len);
		}

		public void write(byte b[]) throws IOException {
			fos.write(b);
		}

		public void write(int b) throws IOException {
			fos.write(b);
		}

		public void discard() throws IOException {
			if (!hasClosed)
				fos.close();
			tempFile.delete();
		}
	}

	/**
	 * <p>Provides a facility for reading the temporary stream.</p>
	 * <p>Responsibilities:
	 * <ul>
	 * 	<li> Reads the stream from disk
	 *  <li> Discard the storage after repeated reads have completed
	 * </ul>
	 * </p>
	 * <p>Collaborators:
	 * <ul>
	 * 	<li> TemporaryFileOuputStream - used for storage
	 * </ul>
	 * </p>
	 */
	static public class TemporaryBufferedInputStream extends InputStream {
		private File tempFile;
		private FileInputStream fileStream;
		private BufferedInputStream bufferedStream;
		boolean alreadyClosed;

		public TemporaryBufferedInputStream(TemporaryFileOuputStream tfos)
				throws IOException {
			tempFile = tfos.tempFile;
			prepare();
		}

		public void prepare() throws IOException {
			close();
			alreadyClosed = false;
			fileStream = new FileInputStream(tempFile);
			bufferedStream = new BufferedInputStream(fileStream);
		}

		public void discard() throws IOException {
			close();
			tempFile.delete();
		}

		public int available() throws IOException {
			return bufferedStream.available();
		}

		public void close() throws IOException {
			if (alreadyClosed)
				return;
			alreadyClosed = true;
			if (bufferedStream != null)
				bufferedStream.close();
		}

		public synchronized void mark(int readlimit) {
			bufferedStream.mark(readlimit);
		}

		public boolean markSupported() {
			return bufferedStream.markSupported();
		}

		public int read() throws IOException {
			return bufferedStream.read();
		}

		public int read(byte b[]) throws IOException {
			return bufferedStream.read(b);
		}

		public int read(byte b[], int off, int len) throws IOException {
			return bufferedStream.read(b, off, len);
		}

		public synchronized void reset() throws IOException {
			bufferedStream.reset();
		}

		public long skip(long n) throws IOException {
			return bufferedStream.skip(n);
		}
	}
}